package com.basker.pisces.service.exception;

import java.io.IOException;
import java.util.List;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.basker.pisces.service.dto.DefaultServiceResult;
import com.basker.pisces.service.dto.IServiceResult;
import com.basker.pisces.service.dto.ServiceResultFactory;

/**
 * 服务端全局的异常处理器
 *
 * @author hangwen
 */
@RestControllerAdvice
@ResponseBody
public class ServiceExceptionHandler {

    private static final Logger logger = LoggerFactory.getLogger(ServiceExceptionHandler.class);

    /**
     * IO异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler
    @ResponseBody
    public DefaultServiceResult<String> handle(IOException ex) {
        return ServiceResultFactory.error(ex.getMessage());
    }

    /**
     * 消息头缺失参数的异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler
    @ResponseBody
    public DefaultServiceResult<String> handle(MessageHeaderNotFoundException ex) {
        return ServiceResultFactory.error(ex.getMessage());
    }

    /**
     * 处理方法参数验证的异常，拼接处友好的消息返回给客户端
     *
     * @param ex
     * @return
     */
    @ExceptionHandler
    @ResponseBody
    public DefaultServiceResult<String> handle(MethodArgumentNotValidException ex) {
        BindingResult bindingResult = ex.getBindingResult();
        String message = getSpringObjectErrorsMessage(null, bindingResult.getAllErrors());

        return ServiceResultFactory.error(message);
    }

    /**
     * 处理封装调用其他服务发生错误的异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler
    @ResponseBody
    public IServiceResult<?> handle(ServiceResultWrapperException ex) {
        return ex.toResult();
    }

    /**
     * 处理意料之外的运行时异常，通常来说：就是bug......也可能是其他尚未被处理的运行时异常
     *
     * @param ex
     * @return
     */
    @ExceptionHandler
    @ResponseBody
    public DefaultServiceResult<String> handleException(RuntimeException ex) {
        DefaultServiceResult<String> result = resovleException(ex);
        if (result != null) {
            return result;
        }

        if (logger.isErrorEnabled()) {
            logger.error("ServiceExceptionHandler catch a unhandled runtime exception!", ex);
        }

        return ServiceResultFactory.error(ex.getMessage());
    }

    private String getSpringObjectErrorsMessage(String message,
                                                List<org.springframework.validation.ObjectError> errors) {
        Stream<String> errorsMessages = errors.stream().map(error -> error.getDefaultMessage());
        String joinedMessage = String.join("", errorsMessages.toArray(s -> new String[s]));

        return !StringUtils.isEmpty(joinedMessage) ? joinedMessage : message;
    }

    private DefaultServiceResult<String> resolveServiceErrorResult(IServiceErrorResult serviceErrorResult) {
        int status = serviceErrorResult.getStatus();
        String message = serviceErrorResult.getMessage();

        return ServiceResultFactory.error(status, message);
    }

    private DefaultServiceResult<String> resovleException(RuntimeException ex) {
        if (ex instanceof IServiceErrorResult) {
            return this.resolveServiceErrorResult((IServiceErrorResult) ex);
        }

        return null;
    }

}
